package cn.jasonone.jfx;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.jasonone.jfx.config.properties.JfxProperties;
import cn.jasonone.jfx.mananger.SceneManager;
import cn.jasonone.jfx.mananger.StageManager;
import com.sun.javafx.application.LauncherImpl;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.application.Preloader;
import javafx.stage.Stage;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;

import javax.annotation.Resource;

/**
 * @author xujie
 * @version 1.0
 * @date 2021/12/21 9:58
 */
@ComponentScan("cn.jasonone.jfx")
public abstract class JfxApplication extends Application implements ApplicationRunner {
    @Resource
    private StageManager stageManager;
    @Resource
    private SceneManager sceneManager;
    @Resource
    private JfxProperties jfxProperties;

    @Override
    public final void init() throws Exception {
        notifyPreloader(new JfxPreloader.LabelNotification("正在启动Springboot..."));
        SpringApplication.run(getClass(), getParameters().getRaw().toArray(new String[0]));
    }

    @Override
    public final void start(Stage primaryStage) throws Exception {

    }

    /**
     * 框架启动完成后的回调
     *
     * @param primaryStage 主舞台对象
     */
    public abstract void startStage(Stage primaryStage);

    /**
     * 初始化,模板方法
     */
    public void initialize() throws InterruptedException {}

    @Override
    public void run(ApplicationArguments args) throws Exception {
        initialize();
        // SpringBoot启动完成,通知预加载器加载完成
        notifyPreloader(new JfxPreloader.LabelNotification("Springboot启动完成"));
        Platform.runLater(() -> {
            Assert.notNull(jfxProperties.getPrimaryController(), "主控制器未指定");
            sceneManager.bindRootParent(jfxProperties.getPrimaryController());
            stageManager.bindScene(sceneManager.getPrimaryScene());
            startStage(stageManager.getPrimaryStage());
        });
    }

    public static void launch(Class<? extends Application> appClass, String... args) {
        launch(appClass, JfxPreloader.class, args);
    }

    public static void launch(String... args) {
        System.setProperty("javafx.preloader", JfxPreloader.class.getName());
        StackTraceElement[] cause = Thread.currentThread().getStackTrace();
        Class appClass = null;
        for (StackTraceElement se : cause) {
            appClass = ClassUtil.loadClass(se.getClassName(), false);
            if (JfxApplication.class != appClass && JfxApplication.class.isAssignableFrom(appClass)) {
                break;
            }
        }
        LauncherImpl.launchApplication(appClass, args);
    }

    public static void launch(Class<? extends Application> applicationType, Class<? extends Preloader> preloaderClass, String[] args) {
        System.setProperty("javafx.preloader", preloaderClass.getName());
        Application.launch(applicationType, args);
    }
}
